#include "ThreadCache.h"
#include "CentralCache.h"

// 线程申请内存块资源
void* ThreadCache::Allocate(size_t size)
{
    assert(size <= MAX_BYTES);
    //获取对齐后的内存大小和哈希桶下标
    size_t alignSize = UtilClass::RoundUp(size);
    size_t index = UtilClass::Index(size);

    //在线程内存池中获取size大小的内存资源
    if(!_tc_freelists[index].Empty())
    {
        //将其从自由链表中取下来，并返回给线程
        void *obj = _tc_freelists[index].PopFront();
        return obj;
    }
    //如果线程内存池没有的话，就需要向中心缓存申请了
    else
    {
        return FetchFromCentralCache(size, index);
    }

}
// 线程释放内存块资源
void ThreadCache::Deallocate(void *ptr, size_t size)
{
    assert(ptr);
    size_t index = UtilClass::Index(size);
    //将内存块链入到线程内存池的指定哈希桶中
    _tc_freelists[index].PushFront(ptr);
    //判断链表中内存块的个数是否大于一次可以申请的内存块个数，如果大于的话，就将MaxSize个节点还给中心内存
    if(_tc_freelists[index].Num() > _tc_freelists[index].MaxSize())
    {
        //将MaxSize个节点取出来
        size_t count = _tc_freelists[index].MaxSize();
        void* rangeList = _tc_freelists[index].PopRange(count);
        //将内存给中心缓存
        CentralCache::GetInstance()->ReleaseListToCentralCache(rangeList, size);
    }
}
//从中心缓存中获取一批内存块
void* ThreadCache::FetchFromCentralCache(size_t size, size_t index)
{
    assert(size <= MAX_BYTES);
    //1. 计算一次申请多少个内存块
    size_t batchNum = std::min(_tc_freelists[index].MaxSize(), UtilClass::FetchBlockNum(size));

    //2. 申请内存块
    void* start = nullptr;
    void* end = nullptr;
    size_t actualNum = CentralCache::GetInstance()->FetchRangeObj(size, start, end, batchNum);
    //判断一下是否申请到空间，如果没有就报错，因为中心缓存没有空间会向页缓存要，页缓存没有空间会向系统申请，系统没有空间了就出问题了。
    assert(actualNum > 0);

    //3. 将获取的内存链挂载到对应的线程内存池哈希桶中
    if(start == end) return start;
    //取出第一个内存块
    void* obj = start;
    start = NextObj(start);
    NextObj(obj) = nullptr;
    //计算剩下的内存块个数
    size_t num = 1;
    void* cur = start;
    while(cur != end)
    {
        cur = NextObj(cur);
    }
    NextObj(end) = nullptr;
    //插入到自由链表
    _tc_freelists[index].PushRange(start, end, num);

    return obj;
}